/*************************************************************************
  > File Name: server.c
  > Author: QiyangXia
  > Mail: 834061456@qq.com 
  > Created Time: 2022年02月17日 星期四 18时55分56秒
 ************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include <errno.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#include<sqlite3.h>

static int user_no=0;
static int cnt=0;
static int num=0;
static char* user_name[10]={0};
static char* user_pwd[10]={0};
sqlite3 *engine=NULL;
char *errmsg=NULL;
static char* hist_name[20]={0};
static char* hist_word[20]={0};
static char* hist_data[20]={0};


int hiscallback(void *prar,int f_num,char **f_name,char **f_word);
int look_for_word(void *prar,int f_num,char **f_value,char **f_name);
int callback(void *prar,int f_num,char **f_value,char **f_name);
void downlown_dict();
void str_break(char *word,char *mean,char *src);
int server_main_loop(int servfd);
int create_tcp_server_socket(char *ipaddr,unsigned short port);
int main(int argc, char *argv[])
{
	int servfd = -1;
	int iport = -1;

	if(argc < 3)
	{
		printf("The argument is too few\n");
		return 1;
	}

	//打开sqlite数据库
	if(0!=sqlite3_open("hw_onlinedir.db",&engine))
	{
		printf("sqlite3_open:%s\n",sqlite3_errmsg(engine));
		sqlite3_free(errmsg);
		errmsg=NULL;
		exit(EXIT_FAILURE);
	}
	printf("................sqlite3_open success.................\n");
	//	导入字典内容，执行一遍即可
	//	downlown_dict();


	sscanf(argv[2],"%d",&iport);
	if(iport < 0 || iport > 0xFFFF)
	{
		printf("The port is invalid\n");
		return 2;
	}

	servfd = create_tcp_server_socket(argv[1],(unsigned short)iport);
	if(servfd < 0)
	{
		printf("create_tcp_server_socket failed\n");
		return 3;
	}

	server_main_loop(servfd);

	sqlite3_free(errmsg);
	errmsg=NULL;
	close(servfd);
	servfd = -1;

	return 0;
}


int create_tcp_server_socket(char *ipaddr,unsigned short port)
{
	int servfd = -1;
	struct sockaddr_in servaddr;
	int ret = 0;

	servfd = socket(AF_INET,SOCK_STREAM,0);
	if(servfd < 0)
	{
		printf("call socket function failed\n");
		return -1;
	}

	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	inet_aton(ipaddr,&servaddr.sin_addr);

	ret = bind(servfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
	ret += listen(servfd,6);
	if(ret < 0)
	{
		close(servfd);
		servfd = -1;
		perror("bind or listen failed:");
		return -1;
	}

	return servfd;
}

void * handle_client_data(void *arg);
int server_main_loop(int servfd)
{
	int datafd = -1;
	struct sockaddr_in cliaddr;
	socklen_t socklen; 
	pthread_t tid;
	int ret = 0;

	while(1)
	{
		socklen = sizeof(cliaddr);
		//datafd = accept(servfd,NULL,NULL);
		datafd = accept(servfd,(struct sockaddr *)&cliaddr,&socklen);
		if(datafd < 0)
		{
			if(errno == EINTR)
			{//本次错误是信号引起，可会忽略本错误
				continue;
			}
			else
			{
				perror("accept failed:");
				break;
			}
		}
		printf("client ipaddr = %s\n",inet_ntoa(cliaddr.sin_addr));
		printf("client port = %d\n",ntohs(cliaddr.sin_port));
		ret = pthread_create(&tid,NULL,handle_client_data,(void *)(long)datafd);
		if(ret != 0)	
		{
			close(datafd);
			datafd = -1;
			continue;
		}
	}
}

void * handle_client_data(void *arg)
{
	int datafd = (int)(long)arg;
	pthread_detach(pthread_self());
	char choose[10]={0};
	char name[20]={0};
	char pwd[20]={0};
	char buf[512]={};
	int ret=0;
	char SQL[128]={0};
	char word[25]={0};
	char mean[256]={0};
	int i=0;

	while(1)
	{ //操作指令接收,决定是登录还是注册
		bzero(choose,sizeof(choose));
		if(recv(datafd,choose,sizeof(choose),0)<0)
		{
			perror("recver");
			goto DONE;
		}
		//只有收到注册指令或登录指令才退出循环
		if(0==strcmp(choose,"1") || 0==strcmp(choose,"2" ))
		{
			;
		}else{
			continue;
		}

		//发送空字符串,防止客服端阻塞
		if(send(datafd," ",1,0)<0)
		{
			;
		}
		//接收用户名
		ret = recv(datafd, name, sizeof(name), 0);
		if (ret < 0) {
			perror("recv");
			goto DONE;
		}
		if(send(datafd," ",1,0)<0)
		{
			;
		}
		//接收密码
		ret = recv(datafd, pwd, sizeof(pwd), 0);
		if (ret < 0) {
			perror("recv");
			goto DONE;
		}

		if(0==strcmp(choose,"1"))
		{
			user_no++;
			sprintf(SQL,"INSERT INTO user VALUES(%d,'%s','%s')",user_no,name,pwd);
			if(0!=sqlite3_exec(engine,SQL,NULL,NULL,&errmsg))
			{
				printf("sqlite3_errmsg:%s\n",errmsg);
				goto DONE;
			}
		}
		if(0==strcmp(choose,"2"))
		{
			if(0!=sqlite3_exec(engine,"SELECT * FROM user",callback,NULL,&errmsg))
			{
				printf("this sqlite3_errmsg:%s\n",errmsg);
				exit(EXIT_FAILURE);
			}
			int i=0;
			for(i=0;i<cnt;i++)
			{
				int iret=0;
				int pret=0;
				iret=strcmp(name,user_name[i]);
				pret=strcmp(pwd,user_pwd[i]);
				if(0==iret && 0==pret)
				{
					strcpy(buf,"login success!!!");
					send(datafd,buf,strlen(buf),0);
					printf("...............有用户上线.................\n");
					break;
				}
			}
			if(i==cnt)
			{
				strcpy(buf,"login fail!!");
				send(datafd,buf,sizeof(buf),0);
				goto DONE;
			}
			break;
		}
	}
	while (1) 
	{
		bzero(word,sizeof(word));
		bzero(mean,sizeof(mean));
		ret=recv(datafd,word,sizeof(word),0);
		printf("%s\n",word);
		if(ret<0){
			perror("recv");
			break;
		}
		else if (ret == 0)
		{
			printf("write close!\n");
			break;
		}

		if(0==strcmp(word,"#exit"))
		{
			;
		}else if(0==strcmp(word,"#hist"))
		{
			sprintf(SQL,"SELECT * FROM Histroy");
			if(0!=sqlite3_exec(engine,SQL,hiscallback,NULL,&errmsg))
			{
				fprintf(stderr,"sqlite3_errmsg:%s\n",errmsg);
				exit(EXIT_FAILURE);
			}
			bzero(buf,sizeof(buf));
			for(int j=0;j<num;j++)
			{
				//printf("%s--%s:%s\n",hist_name[j],hist_word[j],hist_data[j]);
				strcat(buf,hist_name[j]);
				strcat(buf,hist_word[j]);
				strcat(buf,hist_data[j]);
				strcat(buf,"\n");
			}
			send(datafd,buf,512,0);


		}else{

			sprintf(SQL,"INSERT INTO Histroy VALUES('%d','%s','%s',(datetime('now','localtime')))",i++,name,word);
			int ret = sqlite3_exec(engine,SQL,NULL,NULL,&errmsg);
			if(ret!=SQLITE_OK){
				printf("error: %s\n",errmsg);
				break;
			}

			sprintf(SQL,"SELECT * FROM dict WHERE Word='%s'",word);
			if(0!=sqlite3_exec(engine,SQL,look_for_word,(void*)mean,&errmsg))
			{
				printf("sqlite3_errmsg:%s\n",errmsg);
				break;
			}    

			//没有找到结果
			if(strlen(mean)==0)
			{ 
				send(datafd,"find failure!",20,0);
			}
			else
			{
				send(datafd,mean,strlen(mean),0);
			}
		}
	}
	printf("................用户下线...................\n");

DONE:
	close(datafd);
	datafd = -1;
	pthread_exit(NULL);
}



int hiscallback(void *prar,int f_num,char **f_value,char **f_name)
{
   // int i;
   // for(i=0;i<f_num;i++)
    //{
      //  printf("%-5s:%s\n",f_name[i],f_value[i]);
   // }
   //  printf("%s\n",f_value[1]);
    // printf("%s\n",f_value[2]);
    // printf("%s\n",f_value[3]);
    hist_name[num]=(char *)malloc(10*sizeof(char));
    memcpy(hist_name[num],f_value[1],sizeof(f_value[1])+2);
    
    hist_word[num]=(char*)malloc(25*sizeof(char*));
    memcpy(hist_word[num],f_value[2],sizeof(f_value[2])+2);

    hist_data[num]=(char*)malloc(60*sizeof(char*));
    memcpy(hist_data[num],f_value[3],sizeof(f_value[3])+2);

	num++;

    return 0;
}

void downlown_dict()
{
	char dict_buff[512]={0};
	char dict_word[25]={0};
	char dict_mean[256]={0};
	char SQL[512]={0};
	FILE *fp=NULL;
	fp=fopen("dict.txt","r");
	int i=0;

	if(fp!=NULL)
	{
		while(fgets(dict_buff,sizeof(dict_buff),fp)!=NULL)
		{
			str_break(dict_word,dict_mean,dict_buff);
			snprintf(SQL,512,"INSERT INTO dict VALUES(%d,'%s','%s');",i++,dict_word,dict_mean);
			int ret = sqlite3_exec(engine,SQL,NULL,NULL,&errmsg);
			if(ret!=SQLITE_OK){
				printf("error: %s\n",errmsg);
				break;
			}
			bzero(dict_buff,sizeof(dict_buff));
			bzero(dict_word,sizeof(dict_word));
			bzero(dict_mean,sizeof(dict_mean));
			bzero(SQL,sizeof(SQL));

		}
	}

}
void str_break(char *word,char *mean,char *src)
{
	while(*src!=' ')
	{
		//用`替换注解中的',否则数据库写入字典数据会在67行结尾报错，导致后续数字写入失败;
		if(*src=='\'')
		{
			*src='`';
		}

		*word=*src;
		word++;
		src++;
	}
	*word='\0';

	while(*src==' ')
	{
		src++;
	}

	while(*src!='\n')
	{
		//同上;
		if(*src=='\'')
		{
			*src='`';
		}

		*mean=*src;
		mean++;
		src++;
	}
	*mean='\0';
}


int callback(void *prar,int f_num,char **f_value,char **f_name)
{
	user_name[cnt]=(char *)malloc(20*sizeof(char));
	strcpy(user_name[cnt],f_value[1]);

	user_pwd[cnt]=(char*)malloc(20*sizeof(char*));
	strcpy(user_pwd[cnt],f_value[2]);
	cnt++;
	return 0;
}


int look_for_word(void *prar,int f_num,char **f_value,char **f_name)
{
	strcpy((char *)prar,f_value[2]);
	return 0;
}
